/*
 * Copyright (c) 2022 NetLOX Inc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package api

import (
	_ "embed"
	"log"
	"os"
	"runtime/debug"
	"time"

	"github.com/go-openapi/loads"
	flags "github.com/jessevdk/go-flags"
	"github.com/loxilb-io/loxilb/api/restapi"
	"github.com/loxilb-io/loxilb/api/restapi/handler"
	"github.com/loxilb-io/loxilb/api/restapi/operations"
	cmn "github.com/loxilb-io/loxilb/common"
	"github.com/loxilb-io/loxilb/options"
	tk "github.com/loxilb-io/loxilib"
)

var (
	ApiReady  bool
	ApiShutOk chan bool
)

// RegisterAPIHooks - routine to register interface for api
func RegisterAPIHooks(hooks cmn.NetHookInterface) {
	handler.ApiHooks = hooks
}

//go:embed swagger.yml
var EmbeddedSwagger []byte

func EmbeddedSwaggerInit() {
	handler.EmbeddedSwagger = EmbeddedSwagger
}

// WaitAPIServerReady - routine to wait till api server is up
func WaitAPIServerReady() {
	for {
		if ApiReady {
			time.Sleep(2 * time.Second)
			return
		}
		time.Sleep(1 * time.Second)
	}
}

func waitApiServerShutOk() {
	for {
		select {
		case <-ApiShutOk:
			return
		}
	}
}

// ApiServerShutOk - Notifier for server to be shutdown on signals
func ApiServerShutOk() {
	ApiShutOk <- true
}

// This file was generated by the swagger tool.
// Make sure not to overwrite this file after you generated it because all your edits would be lost!

// RunAPIServer - routine to start API server
func RunAPIServer() {

	// Stack trace logger
	defer func() {
		if e := recover(); e != nil {
			tk.LogIt(tk.LogCritical, "%s: %s", e, debug.Stack())
		}
		handler.ApiHooks.NetHandlePanic()
		os.Exit(1)
	}()

	if ApiShutOk == nil {
		ApiShutOk = make(chan bool)
	}

	swaggerSpec, err := loads.Embedded(restapi.SwaggerJSON, restapi.FlatSwaggerJSON)
	if err != nil {
		log.Fatalln(err)
	}

	api := operations.NewLoxilbRestAPIAPI(swaggerSpec)
	server := restapi.NewServer(api)
	defer server.Shutdown()

	parser := flags.NewParser(server, flags.Default)
	parser.ShortDescription = "Loxilb Rest API"
	parser.LongDescription = "Loxilb REST API for Baremetal Scenarios"
	server.ConfigureFlags()
	for _, optsGroup := range api.CommandLineOptionsGroups {
		_, err := parser.AddGroup(optsGroup.ShortDescription, optsGroup.LongDescription, optsGroup.Options)
		if err != nil {
			log.Fatalln(err)
		}
	}
	if _, err := parser.Parse(); err != nil {
		code := 1
		if fe, ok := err.(*flags.Error); ok {
			if fe.Type == flags.ErrHelp {
				code = 0
			}
		}
		os.Exit(code)
	}

	server.ConfigureAPI()
	// API server host list
	server.Host = options.Opts.Host
	server.Port = options.Opts.Port

	// HTTPs List
	if options.Opts.TLS {
		server.TLSHost = options.Opts.TLSHost
		server.TLSPort = options.Opts.TLSPort

		server.TLSCertificateKey = options.Opts.TLSCertificateKey
		server.TLSCertificate = options.Opts.TLSCertificate
	}

	api.ServerShutdown = func() {
		waitApiServerShutOk()
		os.Exit(0)
	}
	ApiReady = true
	EmbeddedSwaggerInit()

	if err := server.Serve(); err != nil {
		log.Fatalln(err)
	}

}
